/**
 * 防抖节流工具类
 * 提供防抖、节流、防抖节流组合等功能
 */

/**
 * 防抖函数 - 在事件被触发n秒后再执行回调，如果在这n秒内又被触发，则重新计时
 * @param {Function} func 要防抖的函数
 * @param {number} wait 等待时间（毫秒）
 * @param {boolean} immediate 是否立即执行
 * @returns {Function} 防抖后的函数
 */
export function debounce(func, wait = 300, immediate = false) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      timeout = null;
      if (!immediate) func.apply(this, args);
    };
    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(this, args);
  };
}

/**
 * 节流函数 - 规定在一个单位时间内，只能触发一次函数
 * @param {Function} func 要节流的函数
 * @param {number} limit 时间间隔（毫秒）
 * @param {Object} options 选项
 * @returns {Function} 节流后的函数
 */
export function throttle(func, limit = 100, options = {}) {
  let inThrottle;
  let lastFunc;
  let lastRan;
  
  return function executedFunction(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      lastRan = Date.now();
      inThrottle = true;
    } else {
      clearTimeout(lastFunc);
      lastFunc = setTimeout(() => {
        if ((Date.now() - lastRan) >= limit) {
          func.apply(this, args);
          lastRan = Date.now();
        }
      }, limit - (Date.now() - lastRan));
    }
  };
}

/**
 * 防抖节流组合 - 结合防抖和节流的优点
 * @param {Function} func 要处理的函数
 * @param {number} debounceWait 防抖等待时间
 * @param {number} throttleWait 节流等待时间
 * @returns {Function} 处理后的函数
 */
export function debounceThrottle(func, debounceWait = 300, throttleWait = 100) {
  let debounceTimer;
  let throttleTimer;
  let lastExecTime = 0;
  
  return function executedFunction(...args) {
    const now = Date.now();
    
    // 清除防抖定时器
    clearTimeout(debounceTimer);
    
    // 设置防抖定时器
    debounceTimer = setTimeout(() => {
      // 检查是否满足节流条件
      if (now - lastExecTime >= throttleWait) {
        func.apply(this, args);
        lastExecTime = now;
      } else {
        // 不满足节流条件，设置节流定时器
        clearTimeout(throttleTimer);
        throttleTimer = setTimeout(() => {
          func.apply(this, args);
          lastExecTime = Date.now();
        }, throttleWait - (now - lastExecTime));
      }
    }, debounceWait);
  };
}

/**
 * 高级防抖 - 支持取消和立即执行
 */
export class AdvancedDebounce {
  constructor(func, wait = 300, options = {}) {
    this.func = func;
    this.wait = wait;
    this.immediate = options.immediate || false;
    this.maxWait = options.maxWait;
    this.timeout = null;
    this.maxTimeout = null;
    this.lastCallTime = 0;
    this.lastInvokeTime = 0;
    this.lastArgs = null;
    this.lastThis = null;
    this.result = null;
  }
  
  invokeFunc(time) {
    const args = this.lastArgs;
    const thisArg = this.lastThis;
    
    this.lastArgs = null;
    this.lastThis = null;
    this.lastInvokeTime = time;
    this.result = this.func.apply(thisArg, args);
    return this.result;
  }
  
  leadingEdge(time) {
    this.lastInvokeTime = time;
    this.timeout = setTimeout(this.timerExpired.bind(this), this.wait);
    return this.immediate ? this.invokeFunc(time) : this.result;
  }
  
  remainingWait(time) {
    const timeSinceLastCall = time - this.lastCallTime;
    const timeSinceLastInvoke = time - this.lastInvokeTime;
    const timeWaiting = this.wait - timeSinceLastCall;
    
    return this.maxWait ? 
      Math.min(timeWaiting, this.maxWait - timeSinceLastInvoke) : 
      timeWaiting;
  }
  
  shouldInvoke(time) {
    const timeSinceLastCall = time - this.lastCallTime;
    const timeSinceLastInvoke = time - this.lastInvokeTime;
    
    return (this.lastCallTime === 0) || 
           (timeSinceLastCall >= this.wait) || 
           (timeSinceLastCall < 0) || 
           (this.maxWait && timeSinceLastInvoke >= this.maxWait);
  }
  
  timerExpired() {
    const time = Date.now();
    if (this.shouldInvoke(time)) {
      return this.trailingEdge(time);
    }
    this.timeout = setTimeout(this.timerExpired.bind(this), this.remainingWait(time));
  }
  
  trailingEdge(time) {
    this.timeout = null;
    if (this.lastArgs) {
      return this.invokeFunc(time);
    }
    this.lastArgs = null;
    this.lastThis = null;
    return this.result;
  }
  
  cancel() {
    if (this.timeout !== null) {
      clearTimeout(this.timeout);
    }
    this.lastInvokeTime = 0;
    this.lastArgs = null;
    this.lastCallTime = 0;
    this.lastThis = null;
    this.timeout = null;
  }
  
  flush() {
    return this.timeout === null ? this.result : this.trailingEdge(Date.now());
  }
  
  pending() {
    return this.timeout !== null;
  }
}

/**
 * 高级节流 - 支持取消和立即执行
 */
export class AdvancedThrottle {
  constructor(func, wait = 100, options = {}) {
    this.func = func;
    this.wait = wait;
    this.leading = options.leading !== false;
    this.trailing = options.trailing !== false;
    this.maxWait = options.maxWait;
    this.timeout = null;
    this.lastCallTime = 0;
    this.lastInvokeTime = 0;
    this.lastArgs = null;
    this.lastThis = null;
    this.result = null;
  }
  
  invokeFunc(time) {
    const args = this.lastArgs;
    const thisArg = this.lastThis;
    
    this.lastArgs = null;
    this.lastThis = null;
    this.lastInvokeTime = time;
    this.result = this.func.apply(thisArg, args);
    return this.result;
  }
  
  leadingEdge(time) {
    this.lastInvokeTime = time;
    this.timeout = setTimeout(this.timerExpired.bind(this), this.wait);
    return this.leading ? this.invokeFunc(time) : this.result;
  }
  
  remainingWait(time) {
    const timeSinceLastCall = time - this.lastCallTime;
    const timeSinceLastInvoke = time - this.lastInvokeTime;
    const timeWaiting = this.wait - timeSinceLastCall;
    
    return this.maxWait ? 
      Math.min(timeWaiting, this.maxWait - timeSinceLastInvoke) : 
      timeWaiting;
  }
  
  shouldInvoke(time) {
    const timeSinceLastCall = time - this.lastCallTime;
    const timeSinceLastInvoke = time - this.lastInvokeTime;
    
    return (this.lastCallTime === 0) || 
           (timeSinceLastCall >= this.wait) || 
           (timeSinceLastCall < 0) || 
           (this.maxWait && timeSinceLastInvoke >= this.maxWait);
  }
  
  timerExpired() {
    const time = Date.now();
    if (this.shouldInvoke(time)) {
      return this.trailingEdge(time);
    }
    this.timeout = setTimeout(this.timerExpired.bind(this), this.remainingWait(time));
  }
  
  trailingEdge(time) {
    this.timeout = null;
    if (this.lastArgs) {
      return this.invokeFunc(time);
    }
    this.lastArgs = null;
    this.lastThis = null;
    return this.result;
  }
  
  cancel() {
    if (this.timeout !== null) {
      clearTimeout(this.timeout);
    }
    this.lastInvokeTime = 0;
    this.lastArgs = null;
    this.lastCallTime = 0;
    this.lastThis = null;
    this.timeout = null;
  }
  
  flush() {
    return this.timeout === null ? this.result : this.trailingEdge(Date.now());
  }
  
  pending() {
    return this.timeout !== null;
  }
}

/**
 * 防抖节流组合类
 */
export class DebounceThrottleCombo {
  constructor(func, debounceWait = 300, throttleWait = 100, options = {}) {
    this.func = func;
    this.debounceWait = debounceWait;
    this.throttleWait = throttleWait;
    this.options = options;
    this.debounceTimer = null;
    this.throttleTimer = null;
    this.lastExecTime = 0;
    this.pending = false;
  }
  
  execute(...args) {
    const now = Date.now();
    this.pending = true;
    
    // 清除防抖定时器
    clearTimeout(this.debounceTimer);
    
    // 设置防抖定时器
    this.debounceTimer = setTimeout(() => {
      // 检查是否满足节流条件
      if (now - this.lastExecTime >= this.throttleWait) {
        this.func.apply(this, args);
        this.lastExecTime = now;
        this.pending = false;
      } else {
        // 不满足节流条件，设置节流定时器
        clearTimeout(this.throttleTimer);
        this.throttleTimer = setTimeout(() => {
          this.func.apply(this, args);
          this.lastExecTime = Date.now();
          this.pending = false;
        }, this.throttleWait - (now - this.lastExecTime));
      }
    }, this.debounceWait);
  }
  
  cancel() {
    clearTimeout(this.debounceTimer);
    clearTimeout(this.throttleTimer);
    this.pending = false;
  }
  
  flush() {
    if (this.pending) {
      clearTimeout(this.debounceTimer);
      clearTimeout(this.throttleTimer);
      this.pending = false;
      return this.func.apply(this, arguments);
    }
    return null;
  }
}

/**
 * 创建防抖函数
 * @param {Function} func 要防抖的函数
 * @param {number} wait 等待时间
 * @param {Object} options 选项
 * @returns {Function} 防抖后的函数
 */
export function createDebounce(func, wait = 300, options = {}) {
  if (options.advanced) {
    return new AdvancedDebounce(func, wait, options);
  }
  return debounce(func, wait, options.immediate);
}

/**
 * 创建节流函数
 * @param {Function} func 要节流的函数
 * @param {number} wait 等待时间
 * @param {Object} options 选项
 * @returns {Function} 节流后的函数
 */
export function createThrottle(func, wait = 100, options = {}) {
  if (options.advanced) {
    return new AdvancedThrottle(func, wait, options);
  }
  return throttle(func, wait, options);
}

/**
 * 创建防抖节流组合函数
 * @param {Function} func 要处理的函数
 * @param {number} debounceWait 防抖等待时间
 * @param {number} throttleWait 节流等待时间
 * @param {Object} options 选项
 * @returns {Function} 处理后的函数
 */
export function createDebounceThrottle(func, debounceWait = 300, throttleWait = 100, options = {}) {
  if (options.advanced) {
    return new DebounceThrottleCombo(func, debounceWait, throttleWait, options);
  }
  return debounceThrottle(func, debounceWait, throttleWait);
}

/**
 * 批量创建防抖节流函数
 * @param {Object} configs 配置对象
 * @returns {Object} 包含防抖节流函数的对象
 */
export function createBatchDebounceThrottle(configs) {
  const result = {};
  
  Object.keys(configs).forEach(key => {
    const config = configs[key];
    const { type, func, wait, options = {} } = config;
    
    switch (type) {
      case 'debounce':
        result[key] = createDebounce(func, wait, options);
        break;
      case 'throttle':
        result[key] = createThrottle(func, wait, options);
        break;
      case 'debounceThrottle':
        result[key] = createDebounceThrottle(func, wait, config.throttleWait, options);
        break;
      default:
        console.warn(`Unknown type: ${type}`);
    }
  });
  
  return result;
}

export default {
  debounce,
  throttle,
  debounceThrottle,
  AdvancedDebounce,
  AdvancedThrottle,
  DebounceThrottleCombo,
  createDebounce,
  createThrottle,
  createDebounceThrottle,
  createBatchDebounceThrottle
};
